feat(services): progressive referral rail and compact result rows (#163) - #1982
Conversation
Ledger #163 asked for query-as-H1, a progressive shortlist/compare flow, and no always-on decision panel or giant step rail on /services?q=. Re-measured against main first: most of that had already landed. The query is already the <h1> via SearchResultsHeaderBand, the shortlist bar is already conditional, Compare already exists, and the four-card numbered walkthrough is only mounted on /services/[slug] — ui-tools already asserts it is absent from results. The 2026-07-31 baseline screenshot in the comps folder no longer reflects main. This closes the residual delta to direction B: - Add ServiceReferralProgress, a one-line Search/Shortlist/Compare/Refer dot rail whose active stage is derived from the shortlist state during render. Its accessible name is "Referral progress", deliberately not the "Referral workflow" name the removed walkthrough used, so the existing absence assertion cannot be satisfied by renaming that component back onto this route. Refer is never current here; it is reached on the record. - Compact the result row: drop the Catchment/Eligibility/Cost strip and the confidence pill. Three truncated fields per row turned a scan of 45 crisis services into clipped prose; the untruncated values are one tap away on the record, which is where a referral decision is made. - Add a per-row bookmark wired to account favourites, kept visually and semantically distinct from the shortlist: the bookmark persists across sessions, the shortlist is this search's working set and is not persisted. Its outcome is announced through a visible polite status, because "sign in to save services" is the common guest outcome and hiding it would leave the control looking broken. - Move the shortlist banner below the heading it qualifies. Deliberately unchanged: SearchResultsHeaderBand's count/query weighting. The comp draws the query dominant, but that split is a documented contract (docs/search-chrome-behaviour.md, Results band rules 1-2), is shared by twelve modes, and is visual-baselined from this exact route. The h1-is-the-query outcome this row asked for holds either way. Also unchanged: the Services ModeHome (this row's stop condition) and the filter contract PR #1878 landed. Shortlist copy stays "N shortlisted" rather than the comp's "N in shortlist" — same meaning, and it avoids churning two source-text assertions for no behavioural gain. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYphQZmsBBeqnidpSnAtjE
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 25 minutes Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (12)
Comment |
Travels with the owning PR rather than a ledger-only branch, per AGENTS.md "PR bundling" — these are independent immutable files, so they carry no conflict risk against a concurrent reconcile. - Branch review record for f939131. - issues:done for #163, recording the split explicitly: what was already on main before this PR versus what this PR delivered, and the one part left deliberately undone (the shared band's count/query weighting). - issues:add for the comps-vs-contract divergence that left behind, so the next implementer finds a decision to make rather than a silent gap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYphQZmsBBeqnidpSnAtjE
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f939131860
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex review-and-fix summary
Codex did not merge or modify auto-merge. The existing merge workflow completed the PR. |
… settles AccountDataProvider initialises `ready` to `auth.status !== "authenticated"`, so for a signed-in reader it is false until the favourites GET resolves, and `favourites` is empty for that whole window. `isSaved()` therefore answered "no" for every service — not because nothing was saved, but because nothing had been read yet. The row rendered "Save X to favourites" on a service the reader had already saved, and a tap issued a redundant write inverting a state that was never loaded. The control is now inert until the read settles: native `disabled` (transient inertness, which is what docs/wiring-conventions.md reserves `disabled` for, as against the aria-disabled placeholder pattern for permanently-unavailable actions), no `aria-pressed` at all rather than a confidently wrong one, and an accessible name that says it is loading. `toggleSaved` refuses early too, so a programmatic call cannot invert an unread state either. Regression cover in tests/services-bookmark-readiness.dom.test.tsx, mutation- verified: reverting the gate fails the first case and leaves the second passing, so the test discriminates the defect rather than the feature. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYphQZmsBBeqnidpSnAtjE
Record 216a72e4 on this branch claimed "Fix service bookmark readiness and mutation race" at head 720e7027a9f08e518eb6344e74dfde35d78d5981. Verified against the refs rather than taken at face value, per AGENTS.md "Third-party fix claims stay unverified until checked": - git cat-file -t 720e7027... — object does not exist in this repository. - git diff 285e12d..87e7fcc -- src/components/services/ — empty. No code change had landed under that claim. The ledger records are immutable, so this supersedes rather than edits. The defect the record named was real, and the preceding commit fixes it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYphQZmsBBeqnidpSnAtjE
Summary
#163againstmainbefore building anything, and most of what the row asks for had already landed./services?q=already renders the query as the<h1>throughSearchResultsHeaderBand, the shortlist bar is already conditional on a non-empty selection, Compare already exists, and the four-card numbered walkthrough is mounted only on/services/[slug]—tests/ui-tools.spec.tsalready asserts it is absent from the results route. Thecurrent/baseline screenshot in the comps folder is from 2026-07-31 and no longer reflectsmain. This PR closes the residual delta to direction B rather than rebuilding what is already there.ServiceReferralProgress: a one-line Search / Shortlist / Compare / Refer dot rail whose active stage is derived from the existing shortlist state during render. Its accessible name is "Referral progress", deliberately not the "Referral workflow" name the removed walkthrough used, so the existing absence assertion cannot be quietly satisfied by renaming that component back onto this route. "Refer" is never the current stage here; it is reached on the record.Deliberately unchanged, and worth stating because the comp disagrees:
SearchResultsHeaderBand's count/query weighting. Direction B draws the query dominant and the count small, but that split is a documented contract (docs/search-chrome-behaviour.md, Results band rules 1–2), is shared by twelve modes, and is visual-baselined from this exact route (tests/ui-visual-baseline.spec.ts). The outcome#163actually asks for — the<h1>is the query, not a match count — holds either way. The comp-vs-contract divergence is being captured as its own ledger row rather than resolved silently inside a services PR. Also unchanged: the Services ModeHome (this row's stop condition) and the filter contract that PR #1878 landed on 2026-08-13.One deviation from the comp: the shortlist banner keeps "N shortlisted" rather than "N in shortlist". Same meaning, and it avoids churning two source-text assertions for no behavioural gain.
Verification
npm run verify:pr-localFocused proof before that gate:
(
services-navigator-scope-empty-state.dom.test.tsx,audit-content-services-regressions.test.ts,search-results-band-adoption.test.ts,route-reachability.test.ts— the first two are the ones that pin this file's effect-free contract and its shortlist source text.)Design-system contract, run because the row markup changed:
UI verification not run: the container ships
chromium-1194while the lock pins revision1234, socheck:playwright-browser-revisionfails closed and no local Playwright run is possible. PointingPLAYWRIGHT_CHROMIUM_EXECUTABLE_PATHat the stale shell is forbidden byAGENTS.md. Browser proof for the changed journey therefore rests on the CI Production UI job, which runsui-smokeandui-tools; both were extended in this PR to assert the new rail's stage progression and the compacted row.Risk and rollout
sr-only./api/account/favouritesendpoint already used by the service, form, and differential record pages; no new endpoint, schema, or provider call was introduced.Clinical Governance Preflight
The classifier returns
clinicalRisk: falsefor these paths, so this section is not required — completed anyway because the change alters which clinical fields a referral result row displays.Clinical KB Database(sjrfecxgysukkwxsowpy)On the row-content change specifically: no service data, ranking, or source governance behaviour changed. Only which already-public fields the results row surfaces changed, and the removed fields remain reachable, untruncated, on the record.
Notes
RAG impact: no retrieval behaviour change — this PR touches only the services results presentation layer (services-navigator-page.tsxrendering and its tests). Retrieval, ranking, selection, and scoring are untouched;rankServiceRecords, the facet/scope pipeline, andrelevanceRankMap` are all called exactly as before.legacyShadowAliasesmeasures 118 on cleanorigin/mainwhilescripts/design-system-contract-baseline.jsonpins 119. Verified by running the checker against the unmodified file. That is one unit of stale ratchet slack and belongs to the gate work in ledger#265, not here.Generated by Claude Code